package com.ctshk.rpc.order.custom.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.*;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.model.PageResponse;
import com.ctshk.common.utils.*;
import com.ctshk.rpc.custom.dto.trip.TripScheduleAdvancedDTO;
import com.ctshk.rpc.custom.dto.trip.TripScheduleDTO;
import com.ctshk.rpc.custom.dto.trip.TripScheduleTouristCountDTO;
import com.ctshk.rpc.custom.req.trip.CustomizedTripScheduleDTO;
import com.ctshk.rpc.custom.req.trip.TripScheduleAmountStatisticsReq;
import com.ctshk.rpc.custom.req.trip.TripScheduleTouristCountReq;
import com.ctshk.rpc.custom.service.ICustomizedTripScheduleAmountStatisticsService;
import com.ctshk.rpc.custom.service.ICustomizedTripScheduleService;
import com.ctshk.rpc.custom.service.ICustomizedTripScheduleTouristCountService;
import com.ctshk.rpc.finance.json.AccountJson;
import com.ctshk.rpc.finance.req.bill.BillAddRefundReq;
import com.ctshk.rpc.finance.req.bill.BillOperateRefundReq;
import com.ctshk.rpc.finance.service.IFinanceBillService;
import com.ctshk.rpc.insurance.dto.AcceptDTO;
import com.ctshk.rpc.insurance.dto.CancelDTO;
import com.ctshk.rpc.insurance.dto.InsuranceInsuredDTO;
import com.ctshk.rpc.insurance.dto.OfferDTO;
import com.ctshk.rpc.insurance.req.InsuranceUnderwritingReq;
import com.ctshk.rpc.insurance.req.tp.*;
import com.ctshk.rpc.insurance.service.IInsuranceService;
import com.ctshk.rpc.order.custom.code.CollectionRefundWayIdCode;
import com.ctshk.rpc.order.custom.code.CollectionWayIdCode;
import com.ctshk.rpc.order.custom.code.CurrencyIdCode;
import com.ctshk.rpc.order.custom.constant.Constants;
import com.ctshk.rpc.order.custom.dto.order.ApprovalQuitInfoDTO;
import com.ctshk.rpc.order.custom.dto.order.CustomOrderTouristQuitAddCalculationDTO;
import com.ctshk.rpc.order.custom.dto.order.CustomOrderTouristQuitListDTO;
import com.ctshk.rpc.order.custom.dto.order.CustomOrderTouristQuitNoticeDetailDTO;
import com.ctshk.rpc.order.custom.entity.*;
import com.ctshk.rpc.order.custom.mapper.*;
import com.ctshk.rpc.order.custom.req.order.*;
import com.ctshk.rpc.order.custom.service.*;
import com.ctshk.rpc.order.custom.util.OrderUtil;
import com.ctshk.rpc.order.custom.util.PacificUtil;
import com.ctshk.rpc.order.custom.vo.CustomOrderTouristQuitNoticeAdd;
import com.ctshk.rpc.order.custom.vo.CustomOrderTouristQuitNoticeAddQuitItemJson;
import com.ctshk.rpc.system.dto.MainDataCurrencyQueryDTO;
import com.ctshk.rpc.system.dto.UserDTO;
import com.ctshk.rpc.system.dto.mian.data.MainDataDeductionRulesDTO;
import com.ctshk.rpc.system.dto.mian.data.MainDataDeductionRulesDetailsDTO;
import com.ctshk.rpc.system.dto.mian.data.MainDataNotGroupRulesDTO;
import com.ctshk.rpc.system.req.MainDataCurrencyUpdateStatusReq;
import com.ctshk.rpc.system.req.main.data.MainDataDeductionRulesIdReq;
import com.ctshk.rpc.system.service.IMainDataCurrencyService;
import com.ctshk.rpc.system.service.IMainDataDeductionRulesService;
import com.ctshk.rpc.system.service.ISysDepartmentService;
import com.ctshk.rpc.system.service.ISysUserService;
import com.ctshk.rpc.workflow.dto.ApprovalCheckDTO;
import com.ctshk.rpc.workflow.dto.ApprovalStartDTO;
import com.ctshk.rpc.workflow.service.ISysApprovalService;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * <p>
 * 游客退团 服务实现类
 * </p>
 *
 * @author 叶冠峰
 * @since 2021-02-22
 */
@DubboService
public class CustomizedOrderTouristQuitServiceImpl extends ServiceImpl<CustomizedOrderTouristQuitMapper, CustomizedOrderTouristQuit> implements ICustomizedOrderTouristQuitService {

    @DubboReference
    private ISysUserService sysUserService;
    @DubboReference
    private ISysDepartmentService sysDepartmentService;
    @DubboReference
    private ICustomizedTripScheduleService tripScheduleService;
    //退团扣费规则
    @DubboReference
    private IMainDataDeductionRulesService deductionRulesService;
    @DubboReference
    private INumberService numberService;
    @DubboReference
    private IInsuranceService insuranceService;
    @DubboReference
    private ICustomizedTripScheduleAmountStatisticsService tripScheduleAmountStatisticsService;
    @DubboReference
    private ICustomizedTripScheduleTouristCountService tripScheduleTouristCountService;
    @Autowired
    private ICustomizedOrderDiscountService orderDiscountService;
    @Autowired
    private ICustomizedOrderTouristInfoService orderTouristInfoService;
    @Autowired
    private ICustomizedOrderTouristPriceService orderTouristPriceService;
    //审批服务
    @DubboReference
    private ISysApprovalService sysApprovalService;
    @DubboReference
    private IMainDataCurrencyService mainDataCurrencyService;
    /*@Autowired
    private RedisTemplate<String, Object> redisTemplate;*/

    @Autowired
    private CustomizedOrderTouristQuitMapper orderTouristQuitMapper;
    @Autowired
    private CustomizedOrderAmountStatisticsMapper orderAmountStatisticsMapper;
    @Autowired
    private CustomizedOrderDiscountMapper orderDiscountMapper;
    @Autowired
    private CustomizedOrderTouristQuitNoticeMapper orderTouristQuitNoticeMapper;
    @Autowired
    private CustomizedOrderMapper orderMapper;
    @Autowired
    private CustomizedOrderTouristInfoMapper orderTouristInfoMapper;
    @Autowired
    private CustomizedOrderInsuranceJoinMapper orderInsuranceJoinMapper;
    @Autowired
    private CustomizedOrderInsuranceMapper orderInsuranceMapper;
    @Autowired
    private CustomizedOrderInsurancePriceTouristMapper orderInsurancePriceTouristMapper;
    @Autowired
    private CustomizedOrderReceiptInsuranceMapper orderReceiptInsuranceMapper;
    @Autowired
    private CustomizedOrderReceiptMapper orderReceiptMapper;
    @Autowired
    private CustomizedOrderReceiptTouristMapper orderReceiptTouristMapper;
    @Autowired
    private CustomizedOrderTouristVisaMapper orderTouristVisaMapper;
    @Autowired
    private CustomizedOrderCollectionMapper orderCollectionMapper;

    @DubboReference
    private IFinanceBillService financeBillService;




    /**
     * 游客退团列表
     *
     * @param req
     * @return
     */
    @Override
    public PageResponse<CustomOrderTouristQuitListDTO> list(CustomOrderTouristQuitListReq req) {
        IPage<CustomOrderTouristQuitListReq> pageParam = new Page<>(req.getPageNo(), req.getPageSize());
        IPage<CustomOrderTouristQuitListDTO> pageResult = orderTouristQuitMapper.selectListBySelective(pageParam, req);
        pageResult.getRecords().forEach(dto -> {
            if (dto.getCreateId() != null){
                UserDTO saler = sysUserService.queryCacheUser(dto.getCreateId());
                if (saler != null){
                    dto.setSalePersonName(saler.getFullName());
                    dto.setSalePersonDept(saler.getDept());
                }
            }
            //优惠记录
            BigDecimal discountAmount = orderCollectionMapper.sumDiscountAmountByTourist(dto.getTouristId(),dto.getOrderId(), CollectionWayIdCode.OPERATE_PROMOTION.getCode(),CollectionWayIdCode.BANK_DISCOUNT.getCode());
            if (discountAmount == null){
                discountAmount = BigDecimal.ZERO;
            }
            //折扣金额
            BigDecimal bigDecimal = orderDiscountMapper.sumAmountByTourist(dto.getOrderId(), dto.getTouristId());
            if (bigDecimal != null){
                discountAmount = discountAmount.add(bigDecimal);
            }
            //退优惠金额
            dto.setDiscountAmount(discountAmount);
        });
        PageResponse<CustomOrderTouristQuitListDTO> pageResponse = new PageResponse<>(pageResult.getRecords(),
                pageResult.getCurrent() == 1,
                pageResult.getTotal() <= (pageResult.getCurrent() * pageResult.getSize()),
                pageResult.getTotal(), pageResult.getCurrent(),
                pageResult.getSize());
        return pageResponse;
    }

    /**
     * 申請退團
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result add(CustomOrderTouristQuitAddReq req) {
        //获取团期
        CustomizedTripScheduleDTO tripScheduleDTO = tripScheduleService.queryByScheduleId(req.getScheduleId());
        if (tripScheduleDTO == null){
            throw new BusinessException(SystemError.CUSTOM_3006);
        }
        //旅客信息
        CustomizedOrderTouristInfo touristInfo = orderTouristInfoMapper.selectById(req.getTouristId());
        if (touristInfo == null){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4001);
        }
        //是否有申请退团记录
        QueryWrapper<CustomizedOrderTouristQuit> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("tourist_id",touristInfo.getId());
        queryWrapper.ne("refund_status",4);
        queryWrapper.eq("is_deleted",0);
        CustomizedOrderTouristQuit quit = orderTouristQuitMapper.selectOne(queryWrapper);
        if (quit != null){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4053);
        }
        //扣款金额
        BigDecimal deductionAmount = BigDecimal.ZERO;
        //查询实收金额
        QueryWrapper<CustomizedOrderAmountStatistics> statisticsWrapper = new QueryWrapper<>();
        statisticsWrapper.eq("order_id",req.getOrderId());
        CustomizedOrderAmountStatistics amountStatistics = orderAmountStatisticsMapper.selectOne(statisticsWrapper);
        if (amountStatistics == null){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4008);
        }
        BigDecimal reciveAmount = amountStatistics.getTotalPaidIn();
        //查询优惠金额
        BigDecimal discountAmount = orderDiscountMapper.sumAmountByOrder(req.getOrderId());
        if (discountAmount == null){
            discountAmount = BigDecimal.ZERO;
        }
        //退款金额
        BigDecimal refundAmount = reciveAmount.subtract(discountAmount);
        //当前距离出发日期多少天
        Integer remainDay = 0;
        Long days = LocalDate.now().until(tripScheduleDTO.getDepartureDate().toLocalDate(), ChronoUnit.DAYS);
        if (days.intValue() > 0){
            remainDay = days.intValue();
        }
        TripScheduleAdvancedDTO advancedDTO = tripScheduleDTO.getAdvancedDTO();
        if (advancedDTO != null){
            //查询退团扣费规则
            if (advancedDTO.getDeductionRules() != null && advancedDTO.getDeductionRules().getValue() != null){
                MainDataDeductionRulesIdReq rulesIdReq = new MainDataDeductionRulesIdReq();
                rulesIdReq.setId(advancedDTO.getDeductionRules().getValue());
                MainDataDeductionRulesDTO rulesDTO = null;
                try{
                    rulesDTO = deductionRulesService.query(rulesIdReq);
                }catch (Exception e){
                    throw new BusinessException(SystemError.MAINDATA_4023);
                }
                if (rulesDTO != null && rulesDTO.getRulesDetailsDTOList() != null && rulesDTO.getRulesDetailsDTOList().size() > 0){
                    for (int i=rulesDTO.getRulesDetailsDTOList().size();i>0;i--){
                        MainDataDeductionRulesDetailsDTO detailsDTO = rulesDTO.getRulesDetailsDTOList().get(i - 1);
                        if(remainDay > detailsDTO.getBeforeDepartureDays()){
                            if (detailsDTO.getDeductionRefundType().intValue() == NumberConstant.TWO.getValue()){
                                //部分退
                                if (detailsDTO.getDeductionAmountType().intValue() == NumberConstant.ONE.getValue()){
                                    //固定值
                                    BigDecimal amount = detailsDTO.getDeductionAmount();
                                    deductionAmount = refundAmount.subtract(amount);
                                    refundAmount = amount;
                                }else{
                                    //百分比
                                    BigDecimal amount = refundAmount.multiply(detailsDTO.getDeductionAmount().divide(new BigDecimal(100))).setScale(2, BigDecimal.ROUND_HALF_DOWN);
                                    deductionAmount = refundAmount.subtract(amount);
                                    refundAmount = amount;
                                }
                                break;
                            }
                        }
                    }
                }
            }
        }
        //排除负数情况
        if(refundAmount.compareTo(BigDecimal.ZERO) < 0){
            refundAmount = BigDecimal.ZERO;
        }
        CustomizedOrderTouristQuit saveObject = EntityUtil.copy(req, CustomizedOrderTouristQuit.class);
        //退团单号
        String refundNumber = numberService.getQuitNumber(req.getUserId());
        saveObject.setId(SnowflakeIdWorker.nextId());
        saveObject.setRefundNumber(refundNumber);
        saveObject.setPaidInAmount(touristInfo.getTotalPaidIn());
        saveObject.setTotalReceivables(touristInfo.getTotalReceivables());
        saveObject.setRefundStatus(2);
        saveObject.setDeductionAmount(deductionAmount);
        saveObject.setDiscountAmount(discountAmount);
        saveObject.setRefundAmount(refundAmount);
        LocalDateTime now = LocalDateTime.now();
        saveObject.setGmtCreate(now);
        saveObject.setCreateId(req.getUserId());
        saveObject.setIsDeleted(0);
        boolean save = save(saveObject);
        if (!save){
            throw new BusinessException(SystemError.SYS_437);
        }
        //发起审批
        Long approvalId = startApproval(saveObject.getId(),req.getOrderId(), req.getUserId(),refundAmount);
        saveObject.setApprovalId(approvalId);
        boolean update = updateById(saveObject);
        if (!update){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(saveObject.getId());
    }


    /**
     * 发起审批流程
     * @param id
     * @param userId
     */
    private Long startApproval(Long id,Long orderId, Long userId,BigDecimal amount) {
        Map<String, Object> extendParams = new HashMap<>();
        extendParams.put("id", id);
        try{
            Result<ApprovalStartDTO> approvalResult = sysApprovalService.start(SystemBusinessType.OUTBOUND_CUSTOMIZATION.getCode(),
                    SysApprovalType.LEAVE_OUTCUSTOM.getCode(), orderId,
                    userId, amount, JSON.toJSONString(extendParams));
            if (!approvalResult.isSuccess()) {
                throw new BusinessException(SystemError.CUSTOM_ORDER_4044);
            }
            return approvalResult.getData().getApprovalId();
        }catch (Exception e){
            throw new BusinessException(SystemError.SYS_422);
        }
    }


    /**
     * 处理团期统计
     * @param touristInfo
     * @param userId
     */
    private void dealTripScheduleStatictics(CustomizedOrderTouristInfo touristInfo, Long userId) {
        //更新团期金额统计
        Integer updateStatistics = tripScheduleAmountStatisticsService.updateAmountStatistics(
                new TripScheduleAmountStatisticsReq(touristInfo.getScheduleId(), touristInfo.getGroupFee(), 1, userId, 1));
        if (updateStatistics <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        //更新团期旅客类型统计
        List<TripScheduleTouristCountDTO> countDTOS = tripScheduleTouristCountService.queryBySchedule(touristInfo.getScheduleId());
        if (countDTOS != null && countDTOS.size() > 0){
            List<TripScheduleTouristCountReq> countReqList = new ArrayList<>();
            for (TripScheduleTouristCountDTO countDTO : countDTOS){
                if (countDTO.getTouristTypeId().longValue() == touristInfo.getMainDataId().longValue()){
                    TripScheduleTouristCountReq countReq = new TripScheduleTouristCountReq();
                    countReq.setId(countDTO.getId());
                    countReq.setOrderPeople(countDTO.getOrderPeople()-1);
                    countReq.setModifiedId(userId);
                    countReqList.add(countReq);
                }
            }
            if (countReqList.size() > 0){
                boolean bl = tripScheduleTouristCountService.batchUpdate(countReqList);
                if (!bl){
                    throw new BusinessException(SystemError.SYS_437);
                }
            }
        }
    }


    /**
     * 退團通知書
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<CustomOrderTouristQuitNoticeDetailDTO> notice(CustomOrderTouristQuitIdReq req) {
        CustomizedOrderTouristQuit dbQuit = orderTouristQuitMapper.selectById(req.getQuitId());
        if (dbQuit == null || Objects.equals(dbQuit.getIsDeleted(),1)){
            throw new BusinessException(SystemError.TOUR_ORDER_30022);
        }
        if (!Objects.equals(dbQuit.getRefundStatus(),2) && !Objects.equals(dbQuit.getRefundStatus(),3) && !Objects.equals(dbQuit.getRefundStatus(),5)){
            throw new BusinessException(SystemError.TOUR_ORDER_30023);
        }
        CustomizedOrderTouristInfo touristInfo = orderTouristInfoMapper.selectById(dbQuit.getTouristId());
        CustomizedOrder dbOrder = orderMapper.selectById(dbQuit.getOrderId());
        QueryWrapper<CustomizedOrderTouristQuitNotice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(CustomizedOrderTouristQuitNotice::getQuitId, req.getQuitId());
        CustomizedOrderTouristQuitNotice quitNotice = orderTouristQuitNoticeMapper.selectOne(queryWrapper);
        CustomOrderTouristQuitNoticeDetailDTO dto = null;
        CustomizedTripScheduleDTO tripScheduleDTO = tripScheduleService.queryByScheduleId(dbQuit.getScheduleId());
        if (quitNotice == null){
            //退团通知书
            List<SeriesOrderTouristQuitNoticeAddQuitItemReq> noticeAddQuitItemReqList = new ArrayList<>();
            SeriesOrderTouristQuitNoticeAddQuitItemReq noticeAddQuitItemReq = EntityUtil.copy(dbQuit, SeriesOrderTouristQuitNoticeAddQuitItemReq.class);
            noticeAddQuitItemReq.setCnSurname(touristInfo.getCnSurname());
            noticeAddQuitItemReq.setCnName(touristInfo.getCnName());
            noticeAddQuitItemReq.setEnSurname(touristInfo.getEnSurname());
            noticeAddQuitItemReq.setEnName(touristInfo.getEnName());
            noticeAddQuitItemReq.setGender(touristInfo.getGender());
            noticeAddQuitItemReq.setGroupFee(dbQuit.getDeductionGroupFee());
            noticeAddQuitItemReq.setTouristTypeName(touristInfo.getTouristTypeName());
            noticeAddQuitItemReq.setCollectionFee(dbQuit.getCollectionFee());
            noticeAddQuitItemReqList.add(noticeAddQuitItemReq);

            SeriesOrderTouristQuitNoticeAddReq noticeAddReq = new SeriesOrderTouristQuitNoticeAddReq();
            noticeAddReq.setCustomerRights(tripScheduleDTO.getCustomerRights());
            noticeAddReq.setQuitReason(dbQuit.getQuitReason());
//        noticeAddReq.setCompanyNotes();
            noticeAddReq.setPassengerName(touristInfo.getEnFullname() + "(" + touristInfo.getCnFullname() + ")");
            noticeAddReq.setTourCode(tripScheduleDTO.getTripNumber());
            noticeAddReq.setDays(tripScheduleDTO.getTravelDays());
            noticeAddReq.setDepDate(DateUtil.fmtLocalDate(tripScheduleDTO.getDepartureDate().toLocalDate(),"yyyy-MM-dd"));
            noticeAddReq.setRoute(tripScheduleDTO.getName());
            noticeAddReq.setEnquiryNo(CharUtil.getRandomStr(6));
            noticeAddReq.setEnquiryTime(Constants.QUERY_TIME);
            noticeAddReq.setQuitItemList(noticeAddQuitItemReqList);
            noticeAddReq.setPaidInAmount(touristInfo.getTotalPaidIn());
            noticeAddReq.setRefundAmount(dbQuit.getRefundAmount());
            noticeAddReq.setCollectionFee(touristInfo.getCollectionFee());
            noticeAddReq.setGroupFee(touristInfo.getGroupFee());
            noticeAddReq.setOrderNumber(dbOrder.getOrderNumber());
            noticeAddReq.setReceiptNumber(numberService.getReceiptNumber(req.getUserId()));
            noticeAddReq.setCollectionFee(dbQuit.getCollectionFee());
            UserDTO userInfo = sysUserService.queryCacheUser(req.getUserId());
            if (userInfo != null) {
                noticeAddReq.setCreateUser(userInfo.getFullName());
                noticeAddReq.setDepartmentName(userInfo.getDept());
                noticeAddReq.setAgent(userInfo.getDeptCode());
            }
            quitNotice = new CustomizedOrderTouristQuitNotice();
            quitNotice.setOrderId(dbOrder.getId());
            quitNotice.setScheduleId(dbOrder.getScheduleId());
            quitNotice.setQuitId(dbQuit.getId());
            quitNotice.setTouristName(noticeAddReq.getPassengerName());
            quitNotice.setCustomerRights(noticeAddReq.getCustomerRights());
            quitNotice.setQuitReason(noticeAddReq.getQuitReason());
            quitNotice.setCompanyNotes(noticeAddReq.getCompanyNotes());
            quitNotice.setNotice(JSON.toJSONString(noticeAddReq));
            int insertQuitNotice = orderTouristQuitNoticeMapper.insert(quitNotice);
            if (insertQuitNotice <= 0){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        if (StringUtils.isNotBlank(quitNotice.getNotice())) {
            SeriesOrderTouristQuitNoticeAddReq item = JSON.parseObject(quitNotice.getNotice(), SeriesOrderTouristQuitNoticeAddReq.class);
            dto = EntityUtil.copy(item, CustomOrderTouristQuitNoticeDetailDTO.class);
            if (dto != null) {
                dto.setOrderId(quitNotice.getId());
                dto.setScheduleId(quitNotice.getScheduleId());
                dto.setQuitId(quitNotice.getId());
                dto.setPassengerName(quitNotice.getTouristName());
                dto.setCustomerRights(quitNotice.getCustomerRights());
                dto.setQuitReason(quitNotice.getQuitReason());
                dto.setCompanyNotes(quitNotice.getCompanyNotes());
                dto.setRemark(dbQuit.getRemark());
                dto.setQueryCode(CharUtil.getRandomStr(6));
                TripScheduleAdvancedDTO advancedDTO = tripScheduleDTO.getAdvancedDTO();
                if (advancedDTO != null){
                    dto.setQueryTime(advancedDTO.getCollectionTime());
                }
            }
        }
        return Result.success(dto);
    }

    /**
     * 操作退款
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result confirm(CustomOrderTouristQuitConfirmReq req) {
        CustomizedOrderTouristQuit dbQuit = getById(req.getId());
        if (dbQuit == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        CustomizedOrder dbOrder = orderMapper.selectById(dbQuit.getOrderId());
        if (dbOrder == null) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4008);
        }
        //业务审批
        Result<ApprovalCheckDTO> result = sysApprovalService.check(req.getApprovalId(), req.getUserId(),
                req.getApprovalStatus(), req.getComments());
        if (!result.isSuccess() || result.getData() == null || !result.getData().getIsFinish()) {
            return Result.failed(SystemError.SYS_422);
        }
        //游客统计
        QueryWrapper<CustomizedOrderTouristInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(CustomizedOrderTouristInfo::getOrderId, req.getOrderId());
        queryWrapper.lambda().eq(CustomizedOrderTouristInfo::getId, req.getTouristId());
        CustomizedOrderTouristInfo touristInfo = orderTouristInfoMapper.selectOne(queryWrapper);
        if (touristInfo == null) {
            throw new BusinessException(SystemError.CUSTOM_ORDER_4001);
        }
        //订单统计
        QueryWrapper<CustomizedOrderAmountStatistics> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.lambda().eq(CustomizedOrderAmountStatistics::getOrderId, req.getOrderId());
        CustomizedOrderAmountStatistics statistics = orderAmountStatisticsMapper.selectOne(queryWrapper2);
        if (statistics == null) {
            throw new BusinessException(SystemError.SYS_411);
        }
        //团费
        BigDecimal orderGroupFee = statistics.getTotalTourFee();
        //应收
        BigDecimal orderTotalReceivables = statistics.getTotalReceivables();
        //实收
        BigDecimal orderTotalPaidIn = statistics.getTotalPaidIn();
        //已退款
        BigDecimal orderRefundAmount = statistics.getRefundAmount();
        //代收费用
        BigDecimal orderCollectionFee = statistics.getCollectionFee();
        //调整费用
        BigDecimal orderAdjustmentCost = statistics.getAdjustmentCost();
        //其他金额
        BigDecimal orderOtherAmount = statistics.getOtherAmount();
        //已出单据金额
        BigDecimal orderReceiptedAmount = statistics.getReceiptedAmount();
        //未收
        BigDecimal orderRemainingReceivables = statistics.getRemainingReceivables();
        //团费
        BigDecimal groupFee = touristInfo.getGroupFee();
        //应收
        BigDecimal totalReceivables = touristInfo.getTotalReceivables();
        //实收
        BigDecimal totalPaidIn = touristInfo.getTotalPaidIn();
        //已退款
        BigDecimal refundAmount = touristInfo.getRefundAmount();
        //代收费用
        BigDecimal collectionFee = touristInfo.getCollectionFee();
        //调整费用
        BigDecimal adjustmentCost = touristInfo.getAdjustmentCost();
        //其他金额
        BigDecimal otherAmount = touristInfo.getOtherAmount();
        //已出单据金额
        BigDecimal receiptedAmount = touristInfo.getReceiptedAmount();
        //未收
        BigDecimal remainingReceivables = touristInfo.getRemainingReceivables();
        //扣减
        totalPaidIn = totalPaidIn.subtract(dbQuit.getRefundAmount());
        //团费
        //orderGroupFee = orderGroupFee;
        //应收
        totalReceivables = totalReceivables.subtract(dbQuit.getRefundAmount());
        //实收
        totalPaidIn = totalPaidIn.subtract(dbQuit.getRefundAmount());
        //已退款
        refundAmount = refundAmount.add(dbQuit.getRefundAmount());
        //代收费用
        //collectionFee = collectionFee;
        //调整费用
        //adjustmentCost = adjustmentCost;
        //其他金额
        otherAmount = otherAmount.subtract(dbQuit.getRefundAmount());
        //已出单据金额
        //receiptedAmount = receiptedAmount;
        //未收
        remainingReceivables = remainingReceivables.subtract(dbQuit.getRefundAmount());
        //团费
        //orderGroupFee = orderGroupFee;
        //应收
        orderTotalReceivables = orderTotalReceivables.subtract(totalReceivables);
        //实收
        orderTotalPaidIn = orderTotalPaidIn.subtract(totalPaidIn);
        //已退款
        orderRefundAmount = orderRefundAmount.add(refundAmount);
        //代收费用
        //orderCollectionFee = orderCollectionFee;
        //调整费用
        //orderAdjustmentCost = orderAdjustmentCost;
        //其他金额
        orderOtherAmount = orderOtherAmount.subtract(otherAmount);
        //已出单据金额
        //orderReceiptedAmount = orderReceiptedAmount;
        //未收
        orderRemainingReceivables = orderRemainingReceivables.subtract(remainingReceivables);
        //游客统计
        touristInfo.setGroupFee(groupFee);
        touristInfo.setTotalReceivables(totalReceivables);
        touristInfo.setTotalPaidIn(totalPaidIn);
        touristInfo.setRefundAmount(refundAmount);
        touristInfo.setCollectionFee(collectionFee);
        touristInfo.setAdjustmentCost(adjustmentCost);
        touristInfo.setOtherAmount(otherAmount);
        touristInfo.setReceiptedAmount(receiptedAmount);
        touristInfo.setRemainingReceivables(remainingReceivables);
        int updateInfo = orderTouristInfoMapper.updateById(touristInfo);
        //订单统计
        statistics.setTotalTourFee(orderGroupFee);
        statistics.setTotalReceivables(orderTotalReceivables);
        statistics.setTotalPaidIn(orderTotalPaidIn);
        statistics.setRefundAmount(orderRefundAmount);
        statistics.setCollectionFee(orderCollectionFee);
        statistics.setAdjustmentCost(orderAdjustmentCost);
        statistics.setOtherAmount(orderOtherAmount);
        statistics.setReceiptedAmount(orderReceiptedAmount);
        statistics.setRemainingReceivables(orderRemainingReceivables);
        int updateStatistics = orderAmountStatisticsMapper.updateById(statistics);
        CustomizedOrderTouristQuit updateObject = EntityUtil.copy(req, CustomizedOrderTouristQuit.class);
        updateObject.setRefundStatus(4);
        boolean updateBl = updateById(updateObject);
        if (!updateBl){
            throw new BusinessException(SystemError.SYS_437);
        }
        //是否购买保险
        dealInsurance(req.getOrderId(),req.getUserId(),req.getTouristId());
        //退团通知书
        CustomizedTripScheduleDTO tripScheduleDTO = tripScheduleService.queryByScheduleId(req.getScheduleId());
        List<CustomOrderTouristQuitNoticeAddQuitItemJson> noticeAddQuitItemReqList = new ArrayList<>();
        CustomOrderTouristQuitNoticeAddQuitItemJson noticeAddQuitItemReq = EntityUtil.copy(dbQuit, CustomOrderTouristQuitNoticeAddQuitItemJson.class);
        noticeAddQuitItemReq.setCnSurname(touristInfo.getCnSurname());
        noticeAddQuitItemReq.setCnName(touristInfo.getCnName());
        noticeAddQuitItemReq.setEnSurname(touristInfo.getEnSurname());
        noticeAddQuitItemReq.setEnName(touristInfo.getEnName());
        noticeAddQuitItemReq.setTouristTypeName(touristInfo.getTouristTypeName());
        noticeAddQuitItemReqList.add(noticeAddQuitItemReq);
        CustomOrderTouristQuitNoticeAdd noticeAddReq = new CustomOrderTouristQuitNoticeAdd();
        noticeAddReq.setCustomerRights(tripScheduleDTO.getCustomerRights());
        noticeAddReq.setQuitReason(dbQuit.getQuitReason());
//        noticeAddReq.setCompanyNotes();
        noticeAddReq.setPassengerName(touristInfo.getEnSurname() + " " + touristInfo.getEnName() +
                "(" + touristInfo.getCnSurname() + " " + touristInfo.getCnName() + ")");
//        noticeAddReq.setAgent();
        noticeAddReq.setTourCode(tripScheduleDTO.getTripNumber());
        noticeAddReq.setDays(tripScheduleDTO.getTravelDays());
        noticeAddReq.setDepDate(CharUtil.getWeekDay(tripScheduleDTO.getDepartureDate().getDayOfWeek().getValue()));
        noticeAddReq.setRoute(tripScheduleDTO.getName());
        noticeAddReq.setEnquiryNo(OrderUtil.getRandom6());
        noticeAddReq.setEnquiryTime(Constants.QUERY_TIME);
        noticeAddReq.setQuitItemList(noticeAddQuitItemReqList);
        noticeAddReq.setPaidInAmount(touristInfo.getTotalPaidIn());
        noticeAddReq.setRefundAmount(dbQuit.getRefundAmount());
        noticeAddReq.setGroupFee(touristInfo.getGroupFee());
        noticeAddReq.setOrderNumber(dbOrder.getOrderNumber());
        noticeAddReq.setReceiptNumber(OrderUtil.getReceiptNumberQuit());
        try {
            UserDTO userDTO = sysUserService.queryCacheUser(req.getUserId());
            noticeAddReq.setDepartmentName(userDTO.getDept());
            noticeAddReq.setCreateUser(userDTO.getFullName());
        }catch (Exception e){
            throw new BusinessException(SystemError.SYS_417);
        }
        //新增退团通知书
        CustomizedOrderTouristQuitNotice quitNotice = new CustomizedOrderTouristQuitNotice();
        quitNotice.setOrderId(dbOrder.getId());
        quitNotice.setScheduleId(dbOrder.getScheduleId());
        quitNotice.setQuitId(dbQuit.getId());
        quitNotice.setTouristName(noticeAddReq.getPassengerName());
        quitNotice.setCustomerRights(noticeAddReq.getCustomerRights());
        quitNotice.setQuitReason(noticeAddReq.getQuitReason());
        quitNotice.setCompanyNotes(noticeAddReq.getCompanyNotes());
        quitNotice.setNotice(JSON.toJSONString(noticeAddReq));
        int insert = orderTouristQuitNoticeMapper.insert(quitNotice);
        if (updateInfo <= 0 || updateStatistics <= 0 || insert <= 0){
            throw new BusinessException(SystemError.SYS_437);
        }
        //处理团期统计
        dealTripScheduleStatictics(touristInfo,req.getUserId());

        //财务操作退款
        BillOperateRefundReq req1 = new BillOperateRefundReq();
        req1.setBillNumber(dbQuit.getRefundNumber());
        req1.setBusinessType(SystemBusinessType.OUTBOUND_CUSTOMIZATION.getCode());
        req1.setUserId(req.getUserId());
        Result result1 = financeBillService.operateRefund(req1);
        if (result1 == null || !result1.isSuccess()){
            throw new BusinessException(SystemError.SYS_437);
        }

        return Result.success(req.getId());
    }

    /**
     * 封装财务退款请求参数
     * @param order
     * @param tripSchedule
     * @param userDTO
     * @param quit
     * @return
     */
    private BillAddRefundReq packBillAddRefundReq(CustomizedOrder order, CustomizedTripScheduleDTO tripSchedule, UserDTO userDTO, CustomizedOrderTouristQuit quit) {
        BillAddRefundReq req1 = new BillAddRefundReq();
        req1.setBillNumber(quit.getRefundNumber());
        req1.setBusinessType(SystemBusinessType.OUTBOUND_TRAVEL.getCode());
        req1.setCollectionAmount(quit.getRefundAmount());
        req1.setCurrencyId(quit.getCurrencyId());
        req1.setCurrencyName(quit.getCurrency());
        req1.setExchangeRate(quit.getExchangeRate().doubleValue());
        req1.setSaleOrderNumber(order.getOrderNumber());
        req1.setSaleOrderId(order.getId());
        req1.setProductNumber(tripSchedule.getTripNumber());
        req1.setProductName(tripSchedule.getName());
        List<String> resourceInfo = new ArrayList<>();
        resourceInfo.add(tripSchedule.getName());
        req1.setResourceInfo(resourceInfo);
        req1.setSaleUserId(quit.getCreateId());
        req1.setSaleDeptId(userDTO.getDeptId());
        req1.setSaleUserName(userDTO.getFullName());
        req1.setRefundTypeId(quit.getRefundTypeId());
        req1.setRefundType(quit.getRefundType());
        AccountJson refundAccountJson = new AccountJson();
        refundAccountJson.setCardNumber(quit.getRefundAccount());
        req1.setRefundAccountJson(refundAccountJson);
        req1.setRefundTime(quit.getGmtCreate());
        req1.setRefundRemark(quit.getRemark());
        req1.setUserId(userDTO.getId());
        req1.setScheduleId(tripSchedule.getId());
        return req1;
    }

    /**
     * 撤回
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result withdraw(CustomOrderTouristQuitIdReq req) {
        //查询记录
        CustomizedOrderTouristQuit quit = getById(req.getQuitId());
        if (quit == null || Objects.equals(quit.getIsDeleted(),1)){
            throw new BusinessException(SystemError.SYS_411);
        }
        //操作权限
        if (!Objects.equals(req.getUserId(),quit.getCreateId())){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4045);
        }
        //审批中状态才能撤回
        if (!Objects.equals(quit.getRefundStatus(), NumberConstant.TWO.getValue())){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4046);
        }
        //修改
        quit.setIsDeleted(1);
        quit.setModifiedId(req.getUserId());
        boolean bl = updateById(quit);
        if (!bl){
            throw new BusinessException(SystemError.SYS_437);
        }
        //业务审批
        Boolean checkApproval = checkApproval(quit.getApprovalId(), 0, req.getUserId(), null);
        if (!checkApproval){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(quit.getId());
    }

    /**
     * 添加计算
     *
     * @param req
     * @return
     */
    @Override
    public Result addCalculation(CustomOrderTouristQuitAddCalculationReq req) {
        //获取团期
        CustomizedTripScheduleDTO tripScheduleDTO = tripScheduleService.queryByScheduleId(req.getScheduleId());
        if (tripScheduleDTO == null) {
            return Result.failed(SystemError.SYS_411);
        }
        CustomizedOrderTouristInfo statistics = orderTouristInfoMapper.selectById(req.getTouristId());
        /*QueryWrapper<CustomizedOrderAmountStatistics> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(CustomizedOrderAmountStatistics::getOrderId, req.getOrderId());
        CustomizedOrderAmountStatistics statistics = orderAmountStatisticsMapper.selectOne(queryWrapper);*/
        if (statistics == null) {
            return Result.failed(SystemError.SYS_411);
        }
        CustomOrderTouristQuitAddCalculationDTO dto = EntityUtil.copy(req, CustomOrderTouristQuitAddCalculationDTO.class);
        //当前距离出发日期多少天
        long remainDay = LocalDate.now().until(tripScheduleDTO.getDepartureDate(), ChronoUnit.DAYS);
        dto.setRemainDay(remainDay);
        //实收金额
        BigDecimal totalPaidIn = statistics.getTotalPaidIn();
        //退款金额
        BigDecimal refundAmount = new BigDecimal(0);
        //查询优惠金额
        BigDecimal discountAmount = new BigDecimal(0);
        QueryWrapper<CustomizedOrderCollection> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.lambda().eq(CustomizedOrderCollection::getOrderId, req.getOrderId());
        queryWrapper2.lambda().eq(CustomizedOrderCollection::getTouristId, req.getTouristId());
        queryWrapper2.lambda().and(object -> object.eq(CustomizedOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.BANK_PREFERENCE.getCode())
//                .or().eq(SeriesOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.POINTS.getCode())
                .or().eq(CustomizedOrderCollection::getCollectionWayId, CollectionRefundWayIdCode.OPERATE_PROMOTION.getCode()));
        queryWrapper2.lambda().eq(CustomizedOrderCollection::getIsDeleted, IsDeletedCode.NO.getCode());
        List<CustomizedOrderCollection> collectionList = orderCollectionMapper.selectList(queryWrapper2);
        for (CustomizedOrderCollection collection : collectionList) {
            discountAmount = discountAmount.add(collection.getPaidInAmount());
        }
        //扣款金额
        BigDecimal deductionAmount = new BigDecimal(0);
        MainDataNotGroupRulesDTO notGroupRules = null;
        MainDataDeductionRulesDTO rulesDTO = null;
        if (tripScheduleDTO.getAdvancedDTO().getDeductionRules() != null){
            //退团扣费规则
            if (tripScheduleDTO.getAdvancedDTO().getDeductionRules() != null && tripScheduleDTO.getAdvancedDTO().getDeductionRules().getValue() != null){
                Long deductionRuleId = tripScheduleDTO.getAdvancedDTO().getDeductionRules().getValue();
                MainDataDeductionRulesIdReq mainDataDeductionRulesIdReq = new MainDataDeductionRulesIdReq();
                mainDataDeductionRulesIdReq.setId(deductionRuleId);
                rulesDTO = deductionRulesService.query(mainDataDeductionRulesIdReq);
                if (rulesDTO != null) {
                    for (int i = rulesDTO.getRulesDetailsDTOList().size(); i > 0; i--) {
                        MainDataDeductionRulesDetailsDTO detailsDTO = rulesDTO.getRulesDetailsDTOList().get(i - 1);
                        if (remainDay > detailsDTO.getBeforeDepartureDays()) {
                            if (Objects.equals(detailsDTO.getDeductionRefundType(), 1)) {
                                deductionAmount = statistics.getTotalPaidIn().subtract(detailsDTO.getDeductionAmount());
                            } else if (Objects.equals(detailsDTO.getDeductionRefundType(), 2)) {
                                if (Objects.equals(detailsDTO.getDeductionAmountType(), 1)) {
                                    deductionAmount = detailsDTO.getDeductionAmount();
                                } else if (Objects.equals(detailsDTO.getDeductionAmountType(), 2)) {
                                    MathContext context = new MathContext(2, RoundingMode.HALF_DOWN);
                                    BigDecimal deductionRatio = detailsDTO.getDeductionAmount().divide(new BigDecimal(100), context);
                                    deductionAmount = statistics.getTotalPaidIn().subtract(discountAmount).multiply(deductionRatio);
                                }
                            }
                            dto.setDeductionAmountType(detailsDTO.getDeductionAmountType());
                            dto.setDeductionRefundType(detailsDTO.getDeductionRefundType());
                            dto.setDeductionValue(detailsDTO.getDeductionAmount());
                            break;
                        }
                    }
                }
            }
        }

        if(req.getDeductionAmount() != null) {
            deductionAmount = req.getDeductionAmount();
        }
        if (deductionAmount.compareTo(BigDecimal.ZERO) < 0){
            deductionAmount = BigDecimal.ZERO;
        }
        refundAmount = statistics.getTotalPaidIn().subtract(deductionAmount);
        dto.setDeductionAmount(deductionAmount);
        dto.setCurrencyRefundAmount(refundAmount);
        dto.setDiscountAmount(discountAmount);
        dto.setTotalPaidIn(totalPaidIn);
        if (req.getCurrencyTypeId() == null || Objects.equals(CurrencyIdCode.HKD.getCode(), req.getCurrencyTypeId())) {
            MainDataCurrencyUpdateStatusReq currencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
            currencyUpdateStatusReq.setId(CurrencyIdCode.HKD.getCode());
            Result<MainDataCurrencyQueryDTO> currencyQueryDTOResult = mainDataCurrencyService.query(currencyUpdateStatusReq);
            if (currencyQueryDTOResult.isSuccess() && currencyQueryDTOResult.getData() != null) {
                MainDataCurrencyQueryDTO currencyQueryDTO = currencyQueryDTOResult.getData();
                dto.setCurrencyCode(currencyQueryDTO.getCurrencyCode());
                dto.setCurrencyType(currencyQueryDTO.getCurrencyName());
                dto.setCurrencyTypeId(CurrencyIdCode.HKD.getCode());
                dto.setExchangeRate(currencyQueryDTO.getMarketExchangeRate());
                dto.setCurrencyRefundAmount(refundAmount);
            }
        } else {
            MainDataCurrencyUpdateStatusReq currencyUpdateStatusReq = new MainDataCurrencyUpdateStatusReq();
            currencyUpdateStatusReq.setId(req.getCurrencyTypeId());
            Result<MainDataCurrencyQueryDTO> currencyQueryDTOResult = mainDataCurrencyService.query(currencyUpdateStatusReq);
            if (currencyQueryDTOResult.isSuccess() && currencyQueryDTOResult.getData() != null) {
                MainDataCurrencyQueryDTO currencyQueryDTO = currencyQueryDTOResult.getData();
                dto.setCurrencyCode(currencyQueryDTO.getCurrencyCode());
                dto.setCurrencyType(currencyQueryDTO.getCurrencyName());
                dto.setCurrencyTypeId(CurrencyIdCode.HKD.getCode());
                dto.setExchangeRate(currencyQueryDTO.getMarketExchangeRate());
                //其他貨幣金額=港幣金額÷對應的門市匯率
                MathContext context = new MathContext(2, RoundingMode.HALF_DOWN);
                dto.setCurrencyRefundAmount(refundAmount.divide(currencyQueryDTO.getMarketExchangeRate(), context));
            }
        }
        dto.setTotalAmount(refundAmount);
        return Result.success(dto);
    }

    /**
     * 审批
     *
     * @param req
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result approval(ApprovalQuitReq req) {
        QueryWrapper<CustomizedOrderTouristQuit> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        CustomizedOrderTouristQuit quit = orderTouristQuitMapper.selectOne(queryWrapper);
        if (quit == null){
            throw new BusinessException(SystemError.SYS_411);
        }
        if (!Objects.equals(quit.getRefundStatus(), NumberConstant.TWO.getValue())){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4048);
        }
        quit.setRefundStatus(req.getType());
        quit.setModifiedId(req.getUserId());
        if (Objects.equals(req.getType(),3)){
            quit.setDeductionCollectionFee(req.getCollectionFee());
            quit.setDeductionGroupFee(req.getGroupFee());
            BigDecimal deductionAmount = quit.getPaidInAmount().subtract(req.getCollectionFee()).subtract(req.getGroupFee());
            quit.setDeductionAmount(deductionAmount);
            BigDecimal subtract = quit.getRefundAmount().subtract(quit.getDeductionAmount());
            if (subtract.compareTo(BigDecimal.ZERO) < 0){
                subtract = BigDecimal.ZERO;
            }
            quit.setRefundAmount(subtract);
            //新增退款认款请求参数
            UserDTO userDTO = sysUserService.queryCacheUser(req.getUserId());
            CustomizedOrder order = orderMapper.selectById(quit.getOrderId());
            CustomizedTripScheduleDTO tripScheduleDTO = tripScheduleService.queryByScheduleId(order.getScheduleId());
            List<BillAddRefundReq> reqList = new ArrayList<>();
            BillAddRefundReq req1 = packBillAddRefundReq(order,tripScheduleDTO,userDTO,quit);
            reqList.add(req1);
            //批量新增财务退款记录
            Result result2 = financeBillService.addRefund(reqList);
            if (result2 == null || !result2.isSuccess()){
                throw new BusinessException(SystemError.SYS_437);
            }
        }
        boolean update = updateById(quit);
        if (!update){
            throw new BusinessException(SystemError.SYS_437);
        }
        //业务审批
        Boolean bl = checkApproval(quit.getApprovalId(), req.getType(), req.getUserId(), req.getRemark());
        if (!bl){
            throw new BusinessException(SystemError.SYS_437);
        }
        return Result.success(quit.getId());
    }

    /**
     * 审批中心-退团信息
     *
     * @param req
     * @return
     */
    @Override
    public Result<ApprovalQuitInfoDTO> approvalQuitInfo(ApprovalIdReq req) {
        QueryWrapper<CustomizedOrderTouristQuit> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("approval_id",req.getApprovalId());
        queryWrapper.eq("is_deleted",0);
        CustomizedOrderTouristQuit quit = orderTouristQuitMapper.selectOne(queryWrapper);
        if (quit == null){
            throw new BusinessException(SystemError.SYS_411);
        }
        ApprovalQuitInfoDTO dto = EntityUtil.copy(quit,ApprovalQuitInfoDTO.class);
        return Result.success(dto);
    }

    /**
     * 退团 - 处理保险
     * @param orderId
     * @param userId
     * @param touristId
     */
    private void dealInsurance(Long orderId,Long userId,Long touristId) {
        //是否参保
        CustomizedOrderInsurancePriceTourist priceTourist = orderInsurancePriceTouristMapper.queryByTourist(orderId,touristId);
        if (priceTourist != null){
            //是 -> 退保
            CustomizedOrderInsurance insurance = orderInsuranceMapper.selectById(priceTourist.getInsuranceId());
            if (insurance == null){
                throw new BusinessException(SystemError.CUSTOM_ORDER_4023);
            }
            //退保请求参数
            List<CancelReq> reqList = new ArrayList<>();
            QueryWrapper<CustomizedOrderInsuranceJoin> joinWrapper = new QueryWrapper<>();
            joinWrapper.eq("insurance_id",insurance.getId());
            joinWrapper.eq("is_deleted",0);
            CustomizedOrderInsuranceJoin join = orderInsuranceJoinMapper.selectOne(joinWrapper);
            if (join != null){
                CancelReq cancelReq = new CancelReq();
                cancelReq.setPolicyNo(join.getPolicyNo());
                cancelReq.setOperatorCode(PacificUtil.OPERATORCODE);
                reqList.add(cancelReq);
                //退保
                List<CancelDTO> cancel = null;
                try {
                    cancel = insuranceService.policyCancel(reqList);
                }catch (Exception e){
                    throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
                }
                if (CollectionUtils.isNotEmpty(cancel)){
                    //退保成功
                    int del = orderInsurancePriceTouristMapper.deleteById(priceTourist.getId());
                    insurance.setIsDeleted(1);
                    insurance.setModifiedId(userId);
                    int update1 = orderInsuranceMapper.updateById(insurance);
                    join.setIsDeleted(1);
                    join.setModifiedId(userId);
                    int update2 = orderInsuranceJoinMapper.updateById(join);
                    //收据作废
                    CustomizedOrderReceiptTourist receiptTourist = orderReceiptTouristMapper.queryTouristInsuranceReceipt(orderId,touristId);
                    if (receiptTourist != null){
                        receiptTourist.setIsDeleted(1);
                        receiptTourist.setModifiedId(userId);
                        int updateReceip = orderReceiptTouristMapper.updateById(receiptTourist);
                        if (updateReceip <= 0){
                            throw new BusinessException(SystemError.SYS_437);
                        }
                    }
                    //更新旅客金额统计
                    CustomizedOrderTouristInfo touristInfo = orderTouristInfoMapper.selectById(priceTourist.getTouristId());
                    if (touristInfo != null){
                        touristInfo.setTotalReceivables(touristInfo.getTotalReceivables().subtract(priceTourist.getAmount()));
                        touristInfo.setTotalPaidIn(touristInfo.getTotalPaidIn().subtract(priceTourist.getAmount()));
                        touristInfo.setReceiptedAmount(touristInfo.getReceiptedAmount().subtract(priceTourist.getAmount()));
                        int update = orderTouristInfoMapper.updateById(touristInfo);
                        if (update <= 0){
                            throw new BusinessException(SystemError.SYS_437);
                        }
                    }
                    if (del <= 0 || update1 <= 0 || update2 <= 0){
                        throw new BusinessException(SystemError.SYS_437);
                    }
                    //该保单其他参保人
                    QueryWrapper<CustomizedOrderInsurancePriceTourist> touristWrapper = new QueryWrapper<>();
                    touristWrapper.eq("insurance_id",insurance.getId());
                    List<CustomizedOrderInsurancePriceTourist> touristList = orderInsurancePriceTouristMapper.selectList(touristWrapper);
                    if (touristList != null && touristList.size() > 0){
                        //还有其他参保人
                        //获取报价
                        int adultNum = 0;
                        int childNum = 0;
                        for (CustomizedOrderInsurancePriceTourist tourist : touristList){
                            if ("28".equals(PacificUtil.getAgeType(tourist.getAge()))){
                                childNum++;
                            }else{
                                adultNum++;
                            }
                        }
                        //保险报价
                        OfferDTO offerDTOS = insuranceOffer(insurance.getBeginDate(),insurance.getEndDate(),insurance.getRationType(),
                                insurance.getApiCode(),childNum,adultNum);
                        //报价金额
                        BigDecimal amount = offerDTOS.getPremium();
                        //总人数
                        int peopleNumber = adultNum + childNum;
                        //前后差额
                        BigDecimal reduceAmount = insurance.getTotalAmount().subtract(amount);
                        CustomizedOrderInsurance insurance1 = EntityUtil.copy(insurance,CustomizedOrderInsurance.class);
                        insurance1.setId(SnowflakeIdWorker.nextId());
                        insurance1.setInsuranceNumber(numberService.getInsuranceNumber(userId));
                        insurance1.setModifiedId(null);
                        insurance1.setGmtModified(null);
                        insurance1.setTotalAmount(amount);
                        insurance1.setPeopleNumber(peopleNumber);
                        insurance1.setIsPrint(0);
                        insurance1.setCreateId(userId);
                        insurance1.setIsDeleted(0);
                        touristList.forEach(tourist1 -> {
                            tourist1.setId(SnowflakeIdWorker.nextId());
                            tourist1.setInsuranceId(insurance1.getId());
                        });
                        //参保
                        InsuranceInsuredDTO insuranceInsuredDTO = null;
                        //封装参保请求参数
                        InsuranceUnderwritingReq insuranceUnderwritingReq = new InsuranceUnderwritingReq();
                        List<AcceptUnderReq> acceptReq = packJoinInsuranceReq(insurance1);
                        insuranceUnderwritingReq.setAcceptReqList(acceptReq);
                        insuranceUnderwritingReq.setUserId(userId);
                        /*UserDTO userDto = sysUserService.queryCacheUser(userId);
                        if (userDto != null){
                            insuranceUnderwritingReq.setDepartment(userDto.getDept());
                            insuranceUnderwritingReq.setDepartmentId(userDto.getDeptId());
                        }*/
                        CustomizedOrder order = orderMapper.selectById(orderId);
                        insuranceUnderwritingReq.setOrderNumber(order.getOrderNumber());
                        insuranceUnderwritingReq.setBusinessType(BusinessTypeCode.CUSTOMIZE.getCode());
                        insuranceUnderwritingReq.setTotalFee(amount);
                        try{
                            insuranceInsuredDTO = insuranceService.sendProposalContent(insuranceUnderwritingReq);
                        }catch (Exception e){
                            throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
                        }
                        List<AcceptDTO> acceptDTOS = insuranceInsuredDTO.getAcceptDTOS();
                        if (insuranceInsuredDTO == null || acceptDTOS == null || acceptDTOS.size() == 0){
                            throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
                        }
                        //参保记录
                        List<CustomizedOrderInsuranceJoin> joinList = new ArrayList<>();
                        for (AcceptDTO acceptDTO : acceptDTOS){
                            CustomizedOrderInsuranceJoin join1 = EntityUtil.copy(acceptDTO, CustomizedOrderInsuranceJoin.class);
                            join1.setId(SnowflakeIdWorker.nextId());
                            join1.setInsuranceId(insurance1.getId());
                            join1.setOrderId(orderId);
                            join1.setCreateId(userId);
                            join1.setGmtCreate(LocalDateTime.now());
                            join1.setIsDeleted(0);
                            joinList.add(join1);
                        }
                        if(joinList.size() > 0){
                            Integer batchJoin = orderInsuranceJoinMapper.insertBatchSomeColumn(joinList);
                            if (batchJoin < joinList.size()){
                                throw new BusinessException(SystemError.SYS_437);
                            }
                        }
                        insurance1.setIsPay(1);
                        insurance1.setModifiedId(userId);
                        int insert = orderInsuranceMapper.insert(insurance1);
                        Integer batch = orderInsurancePriceTouristMapper.insertBatchSomeColumn(touristList);
                        if (insert <= 0 || batch < touristList.size()){
                            throw new BusinessException(SystemError.SYS_437);
                        }
                        //保单收据
                        QueryWrapper<CustomizedOrderReceiptInsurance> receiptInsuranceWrapper = new QueryWrapper<>();
                        receiptInsuranceWrapper.eq("insurance_id",insurance.getId());
                        receiptInsuranceWrapper.eq("is_deleted",0);
                        CustomizedOrderReceiptInsurance receiptInsurance = orderReceiptInsuranceMapper.selectOne(receiptInsuranceWrapper);
                        if (receiptInsurance != null){
                            receiptInsurance.setInsuranceId(insurance1.getId());
                            receiptInsurance.setInsuranceNumber(insuranceInsuredDTO.getInsuranceReceiptNumber());
                            receiptInsurance.setStampDutyPic(insuranceInsuredDTO.getStampDutyPic());
                            receiptInsurance.setTotalAmount(amount);
                            receiptInsurance.setCreateDate(LocalDate.now());
                            receiptInsurance.setCreateId(userId);
                            receiptInsurance.setGmtCreate(LocalDateTime.now());
                            receiptInsurance.setModifiedId(userId);
                            int update = orderReceiptInsuranceMapper.updateById(receiptInsurance);
                            if (update <= 0){
                                throw new BusinessException(SystemError.SYS_437);
                            }
                        }
                        //更新金额统计
                        QueryWrapper<CustomizedOrderAmountStatistics> statisticsWrapper = new QueryWrapper<>();
                        statisticsWrapper.eq("order_id",orderId);
                        CustomizedOrderAmountStatistics statistics = orderAmountStatisticsMapper.selectOne(statisticsWrapper);
                        if (statistics != null){
                            statistics.setTotalReceivables(statistics.getTotalReceivables().subtract(reduceAmount));
                            statistics.setTotalPaidIn(statistics.getTotalPaidIn().subtract(reduceAmount));
                            statistics.setReceiptedAmount(statistics.getReceiptedAmount().subtract(reduceAmount));
                            int update = orderAmountStatisticsMapper.updateById(statistics);
                            if (update <= 0){
                                throw new BusinessException(SystemError.SYS_437);
                            }
                        }
                    }
                }

            }
        }
    }

    /**
     * 封装参保请求参数
     * @param insurance 保单
     * @return
     */
    public List<AcceptUnderReq> packJoinInsuranceReq(CustomizedOrderInsurance insurance) {
        List<AcceptUnderReq> list = new ArrayList<>();
        AcceptUnderReq acceptReq = new AcceptUnderReq();
        //投保人
        CustomizedOrderTouristInfo applyer = orderTouristInfoMapper.selectById(insurance.getPolicyHolderId());
        if (applyer != null) {
            //投保人資訊
            ApplicantInfo appliGuRelatedPartyDto = new ApplicantInfo();
            appliGuRelatedPartyDto.setAge(applyer.getBirthday().until(LocalDate.now()).getYears() + "");
            appliGuRelatedPartyDto.setBirthDate(DateUtil.fmtLocalDate(applyer.getBirthday(), "yyyy-MM-dd"));
            appliGuRelatedPartyDto.setEmail(applyer.getEmail());
            appliGuRelatedPartyDto.setIdentifyNumber(applyer.getCertificateNumber());
            appliGuRelatedPartyDto.setInsuredName("张三");
            appliGuRelatedPartyDto.setInsuredEName("张三");
            //证件类型 + 联系地址
            //    String identifyType = PacificUtil.getIdentifyType(applyer.getCertificateTypeId());
            appliGuRelatedPartyDto.setIdentifyType("03");
            appliGuRelatedPartyDto.setSex(applyer.getGender().toString());
            appliGuRelatedPartyDto.setMobilePhone(applyer.getMobile());
            acceptReq.setAppliGuRelatedPartyDto(appliGuRelatedPartyDto);
        }
        //被保人資訊列表
        List<InsuredInfo> guItemAcciListDtoList = new ArrayList<>();
        //旅客参保信息
        QueryWrapper<CustomizedOrderInsurancePriceTourist> touristWrapper = new QueryWrapper<>();
        touristWrapper.eq("insurance_id", insurance.getInsuranceRecordId());
        touristWrapper.eq("order_id", insurance.getOrderId());
        List<CustomizedOrderInsurancePriceTourist> touristList = orderInsurancePriceTouristMapper.selectList(touristWrapper);
        if (touristList != null && touristList.size() > 0) {
            //被保人資訊列表
            for (CustomizedOrderInsurancePriceTourist tourist : touristList) {
                InsuredInfo guItemAcciListDto = new InsuredInfo();
                guItemAcciListDto.setAge(tourist.getAge().toString());
                guItemAcciListDto.setBirthday(DateUtil.fmtLocalDate(tourist.getBirthday(), "yyyy-MM-dd"));
                guItemAcciListDto.setSex(tourist.getSex().toString());
                guItemAcciListDto.setClientCName(tourist.getEnSurname() + tourist.getEnName());
                guItemAcciListDto.setIdentifyNoA(tourist.getCertificateNumber());
                //证件类型
                //    String identifyTypeA = PacificUtil.getIdentifyType(tourist.getCertificateTypeId());
                guItemAcciListDto.setIdentifyTypeA("03");
                //年龄类型
                //    String remark3 = PacificUtil.getAgeType(tourist.getAge());
                guItemAcciListDto.setRemark3("28");
                guItemAcciListDtoList.add(guItemAcciListDto);
            }
        }
        acceptReq.setGuItemAcciListDtoList(guItemAcciListDtoList);
        //險別咨訊
        acceptReq.setStartDate(DateUtil.fmtLocalDate(insurance.getBeginDate(), "yyyy-MM-dd"));
        acceptReq.setEndDate(DateUtil.fmtLocalDate(insurance.getEndDate(), "yyyy-MM-dd"));
        acceptReq.setStartPlace(insurance.getDeparturePlace());
        acceptReq.setEndPlace(insurance.getDestination());
        list.add(acceptReq);
        return list;
    }


    /**
     * 保险报价
     * @param beginDate
     * @param endDate
     * @param rationType
     * @param apiCode
     * @param childNum
     * @param adultNum
     * @return
     */
    public OfferDTO insuranceOffer(LocalDate beginDate, LocalDate endDate, Integer rationType, String apiCode, Integer childNum, Integer adultNum) {
        OfferReq offerReq = new OfferReq();
        Offer offer = new Offer();
        offer.setStarDate(DateUtil.fmtLocalDate(beginDate,"yyyy-MM-dd"));
        offer.setEndDate(DateUtil.fmtLocalDate(endDate,"yyyy-MM-dd"));
        offer.setRationType(rationType);
        offer.setRiskCode(apiCode);
        offer.setChildCount((long)childNum);
        offer.setPersonCount((long)adultNum);
        offerReq.setData(offer);
        OfferDTO offerDTOS = null;
        try {
            offerDTOS = insuranceService.acciQuotation(offerReq);
        }catch (Exception e){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
        }
        if (offerDTOS == null){
            throw new BusinessException(SystemError.CUSTOM_ORDER_4026);
        }
        return offerDTOS;
    }

    /**
     * 业务审批
     * @param approvalId    审批id(必填)
     * @param userId        审批人id(必填)
     * @param status        状态-ApprovalStatus枚举code 0 撤回 3 审批不通过 4 审批通过(必填)
     * @param comments      通过或拒绝评论说明(非必填)
     * @return
     */
    private Boolean checkApproval(Long approvalId, Integer status, Long userId,String comments){
        Result<ApprovalCheckDTO> result = sysApprovalService.check(approvalId, userId, status, comments);
        if (result != null && result.isSuccess()){
            return result.getData().getIsFinish();
        }
        return false;
    }


}
